/**
 * @file app\tasks\mobus\event\mobus_event.c
 *
 * Copyright (C) 2023
 *
 * mobus_event.c is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author HinsShum hinsshum@qq.com
 *
 * @encoding utf-8
 */

/*---------- includes ----------*/
#include "inc/mobus_event.h"
#include "mobus_device.h"

/*---------- macro ----------*/
/*---------- type define ----------*/
/*---------- variable prototype ----------*/
/*---------- function prototype ----------*/
/*---------- variable ----------*/
/*---------- function ----------*/
bool __attribute__((weak))mobus_evt_broadcast(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    if (evt->broadcast.cmd == MOBUS_BROCAST_CMD_QUERY_ONLINE) {
        if (self->req_access_to_mobus_network) {
            self->req_access_to_mobus_network(self);
        }
    }

    return false;
}

bool __attribute__((weak))mobus_evt_query_status(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    if (evt->unicast.cmd == MOBUS_CMD_QUERY_ONLINE) {
        ack = MOBUS_ACK_OK;
    }
    else if (evt->unicast.cmd == MOBUS_CMD_QUERY_STATUS) {
        if (evt->unicast.length >= 1) {
            ack = MOBUS_ACK_OK;
            if (self->report_status) {
                self->report_status(self, evt->unicast.data[0] & 0xF);
            }
        }
    }
    else if (evt->unicast.cmd == MOBUS_CMD_QUERY_INFO) {
        if (evt->unicast.length > 1) {
            ack = MOBUS_ACK_OK;
            if (self->report_information) {
                self->report_information(self, evt->unicast.data[0]);                
//                self->report_information(self, evt->unicast.data[0],
//                    &evt->unicast.data[1],
//                    evt->unicast.length - 1);
            }
        }
    }
    if (result) {
        *result = ack;
    }

    return true;
}

bool __attribute__((weak))mobus_evt_ack(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    if (self->ack) {
        self->ack(self, evt->ack.send_frame_type,
            evt->ack.length ? evt->ack.data[0] : MOBUS_ACK_OK);
    }

    return false;
}
bool __attribute__((weak))mobus_evt_upgrade(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    if (self->upgrade) {
        self->upgrade(self, evt->unicast.sync);
    }

    return false;
}
bool __attribute__((weak))mobus_evt_command(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    if (evt->unicast.length != 0) {
        if (self->command) {
            self->command(self, evt->unicast.sub_channel, &evt->unicast.data[0],
                evt->unicast.length);
            ack = MOBUS_ACK_OK;
        }
    }
    if (result) {
        *result = ack;
    }

    return true;
}

bool __attribute__((weak))mobus_evt_command_device(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;
    uint8_t channel = ((uint8_t)evt->unicast.number_of_channels << 4) | evt->unicast.sub_channel;
    do {
        if (evt->unicast.length < 7) {
            break;
        }
        if (!self->config_device) {
            break;
        }
        ack = MOBUS_ACK_OK;
    } while (0);
    if (result) {
        *result = ack;
    }

    return true;
}
bool __attribute__((weak))mobus_evt_config_device(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;
    uint8_t devaddr = self->native_address;
    uint8_t number_of_channels = self->channel_nums;
    uint16_t devtype = MOBUS_DEVICE_TYPE_UNKNOWN;
    uint8_t channel = ((uint8_t)evt->unicast.number_of_channels << 4) |
        evt->unicast.sub_channel;

    do {
        if (evt->unicast.length < 7) {
            break;
        }
        if (!self->config_device) {
            break;
        }
        if (evt->unicast.data[0] == 0xAA) {
            devaddr = evt->unicast.data[3];
        }
        if (evt->unicast.data[1] == 0xAA) {
            devtype = ((uint16_t)evt->unicast.data[4] << 8) | evt->unicast.data[5];
        }
        if (evt->unicast.data[2] == 0xAA) {
            number_of_channels = evt->unicast.data[6];
        }
        self->config_device(self, channel, devaddr, devtype, number_of_channels);
        ack = MOBUS_ACK_OK;
    } while (0);
    if (result) {
        *result = ack;
    }

    return true;
}

bool __attribute__((weak))
mobus_evt_restore_factory(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    bool err = true;
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    do {
        if (evt->unicast.length < 1) {
            break;
        }
        if (!self->restore_factory) {
            break;
        }
        if (evt->unicast.data[0] == MOBUS_RESTORE_CMD_CONFIRM) {
            self->restore_factory(self, evt->unicast.sync);
            err = false;
        }
        ack = MOBUS_ACK_OK;
    } while (0);
    if (result) {
        *result = ack;
    }

    return err;
}

static inline void __query_version(mobus_device_t self,
    protocol_mobus_evt_t evt) {
    uint8_t buf[strlen(SYS_VERSION_STRINGS) + 1] = { 0 };

    memcpy(&buf[1], SYS_VERSION_STRINGS, ARRAY_SIZE(buf) - 1);
    protocol_mobus_upload(evt->frame_type, evt->unicast.native_addr,
        self->channel_nums, evt->unicast.sub_channel, buf,
        ARRAY_SIZE(buf));
}

static inline void __query_parameters(mobus_device_t self,
    protocol_mobus_evt_t evt) {
    uint8_t start = evt->unicast.data[0];
    uint8_t numbers = evt->unicast.data[1];
    uint8_t wanted_size = 2 + numbers;
    uint8_t* pbuf = __malloc(wanted_size);

    if (pbuf) {
        pbuf[0] = start;
        pbuf[1] = numbers;
        if (self->get_parameters) {
            self->get_parameters(self, evt->unicast.sub_channel, start, &pbuf[2], numbers);
        }
        else {
            memset(&pbuf[2], 0xFF, numbers);
        }
        protocol_mobus_upload(evt->frame_type, evt->unicast.native_addr,
            self->channel_nums, evt->unicast.sub_channel, pbuf,
            wanted_size);
        __free(pbuf);
    }
}

bool __attribute__((weak))
mobus_evt_query_parameters(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    do {
        if (!evt->unicast.length) {
            break;
        }
        if (evt->unicast.data[0] == 0) {
            ack = MOBUS_ACK_OK;
            __query_version(self, evt);
        }
        if (evt->unicast.length < 2) {
            //TODO:wait add  channlx  sta  
            mobus_evt_query_status(self, evt, result);
            break;
        }
        __query_parameters(self, evt);
        ack = MOBUS_ACK_OK;
    } while (0);
    if (result) {
        *result = ack;
    }

    return true;
}

static inline void __config_parameters(mobus_device_t self,
    protocol_mobus_evt_t evt) {
    uint8_t start = evt->unicast.data[0];
    uint8_t numbers = evt->unicast.data[1];
    uint8_t* pbuf = &evt->unicast.data[2];

    if (self->set_parameters) {
        self->set_parameters(self, evt->unicast.sub_channel, start, pbuf, numbers);
    }
}

bool __attribute__((weak))
mobus_evt_config_parameters(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    do {
        if (evt->unicast.length < 2 || evt->unicast.data[1] == 0 ||
            evt->unicast.data[1] >(evt->unicast.length - 2)) {
            break;
        }
        __config_parameters(self, evt);
        ack = MOBUS_ACK_OK;
    } while (0);
    if (result) {
        *result = ack;
    }

    return true;
}

bool __attribute__((weak))
mobus_evt_update_firmware(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    //    if(self->upgrade) {
    //        self->upgrade(self);
    //        ack = MOBUS_ACK_OK;
    //    }
    if (result) {
        *result = ack;
    }

    return true;
}

bool __attribute__((weak))
mobus_evt_multicast(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    bool err = false;
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    do {
        if (!self->multicast) {
            break;
        }
        if (evt->evt_type == PROTOCOL_MOBUS_EVT_TYPE_GROUP) {
            self->multicast(self, evt->multicast.uid, (uint8_t)evt->frame_type,
                evt->multicast.data[0], evt->multicast.data,
                evt->multicast.length);
            break;
        }
        if (evt->evt_type == PROTOCOL_MOBUS_EVT_TYPE_MULTICAST) {
            if (evt->multicast.length) {
                self->multicast(self, evt->multicast.uid, (uint8_t)evt->frame_type,
                    evt->multicast.data[0], &evt->multicast.data[1],
                    evt->multicast.length - 1);
            }
            break;
        }
        if (evt->evt_type == PROTOCOL_MOBUS_EVT_TYPE_UNICAST) {
            if (evt->unicast.length) {
                err = true;
                ack = MOBUS_ACK_OK;
                self->multicast(self, 0xFFFF, (uint8_t)evt->frame_type,
                    evt->unicast.data[0], &evt->unicast.data[1],
                    evt->unicast.length - 1);
            }
        }
    } while (0);
    if (result && err) {
        *result = ack;
    }

    return err;
}

bool __attribute__((weak))
mobus_evt_set_authinfo(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    do {
      //        if(!self->set_information) {
      //            break;
      //        }
      //        if(evt->unicast.number_of_channels != 0xF ||
      //        evt->unicast.sub_channel != 0xF) {
      //            break;
      //        }
      //        if(evt->unicast.length < 2) {
      //            break;
      //        }
      //        self->set_information(self, evt->unicast.data,
      //        evt->unicast.length);
        ack = MOBUS_ACK_OK;
    } while (0);
    if (result) {
        *result = ack;
    }

    return true;
}
bool __attribute__((weak))
mobus_evt_factory_test(mobus_device_t self, protocol_mobus_evt_t evt,
    mobus_ack_result_t* result) {
    mobus_ack_result_t ack = MOBUS_ACK_DATA_ERR;

    do {
        if (!self->factory_test) {
            break;
        }
        if (!evt->unicast.length) {
            break;
        }
        self->factory_test(self, evt->unicast.data, evt->unicast.length);
        ack = MOBUS_ACK_OK;
    } while (0);
    if (result) {
        *result = ack;
    }

    return true;
}
